/*
The MIT License

Copyright (c) 2010 Michael Webb

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
 */


/**
 * @namespace
 */
CA = {};
if(typeof(Array.prototype.indexOf)=="undefined"){
	Array.prototype.indexOf = function(o){
		for(var i=0;i<this.length;i++){
			if(this[i]===o){
				return i;
			}
		}
		return -1;
	};
}
/**
 * Copies values from source to target, overriding existing values if override is true
 * @param {Object} source The source object
 * @param {Object} target The target object
 * @param {boolean} override If existing properties on target should be overriden
 */
CA.apply = function(source,target,override){
	for(var a in source){
		if(source.hasOwnProperty(a)){
			if(!target[a]||override){
				target[a]=source[a];
			}
		}
	}
};
/**
 * Provides facilities for creating objects representing
 * namespaces starting from the window down.
 * @memberOf CA
 * @function
 * @param {string} ns A period seperated namespace
 * @param {Object} root An optional value representing the root of the namespace (default is the global namespace).
 * @return {Object} The namespace for the name provided
 */
CA.NameSpace = function(ns,root){
	if(typeof(root)==="undefined"){
    	root = window;
	}
	if(arguments.length==2){
		root = arguments[1];			
	}
    var lst = ns;
    if(typeof ns === "string"){
    	lst = ns.split(".");
    }
    for(var i=0;i<lst.length;i++){
        var entry = lst[i];
        if(typeof(root[entry]) == "undefined"){
            root[entry] = {};
        }
        root = root[entry];
    }
    return root;
};
/**
 * @class
 * @static
 */
CA.Errors = {};
/**
 * A factory that returns, constructing if not already existing, subclasses of Error.  Created errors are later available
 * as attributes of CA.Errors.
 * @function Create
 * @param {string} error_name the name of the error class to retrieve/create
 * @return {Function} The constructor for the custom error
 */
CA.Errors.Create = function(error_name) {
	if (error_name == "Create") {
		throw new Error("Invalid error name.");
	}
	if (!CA.Errors[error_name]) {
		/**
		 * An error
		 * @constructor
		 * @param {Object} message
		 * @param {Object} fileName
		 * @param {Object} lineNumber
		 */
		CA.Errors[error_name] = function(message, fileName, lineNumber) {
			this.name = error_name;
			this.message = message || "";
			this.fileName = fileName || location.href;
			if (!isNaN(+lineNumber)) {
				this.lineNumber = +lineNumber;
			} else {
				this.lineNumber = 1;
			}
		};
		CA.Errors[error_name].prototype.toString = Error.prototype.toString;
	}
	return CA.Errors[error_name];
};
/* Interface : provides methods for handling the creation
 * and lookup of interaces.  This is largely borrowed from the
 * work of the book, Pro JavaScript Design Patterns.
 */
(function() {
	var nid = 0;
	var InterfaceId = function ()
	{
	     return nid++;
	};
	var interfaces = {};
	/**
	 * @namespace
	 */
	CA.Interfaces = {};
	/**
	 * Indicates if Interface Keys should be used.  If used, when
	 * an interface is checked, an attribute named '__interfaces__' 
	 * is looked up on the object.  If it does not exist, an array of
	 * that name is added to the object.  Each interface has a unique
	 * (to the browser) key, and the index of that key will be looked up
	 * in the array.  Failing to find the key will then result in a full
	 * inspection of the methods.  Defaults to true;
	 * @property USE_INTERFACE_KEYS
	 * @type boolean
	 */
	CA.Interfaces["USE_INTERFACE_KEYS"] = true;
	/**
	 * The interface class, derived from the book Pro Javascript Design Patterns 
	 * http://apress.com/book/view/159059908x
	 * This class cannot be instantiated directly, but must be created through the
	 * CA.Interfaces.CreateInterface method.
	 * @memberOf CA.Interfaces
	 * @class
	 * @constructor
	 * @param {string} name The name of the interface
	 * @param {Array} methods An array of method names (strings) that must exist on an object to "implement" this interface
	 */
	var Interface = function(name, methods) {
		if (typeof (interfaces[name]) != "undefined") {
			throw new Error("Interface already exists");
		}
		if (arguments.length != 2) {
			throw new Error("Interface called with " + arguments.length	+ " arguments but expected exactly 2");
		}
		this.name = name;
		this.methods = [];
		for ( var i = 0; i < methods.length; i++) {
			if (typeof (methods[i]) != "string") {
				throw new Error("Methods are expected to be of type string");
			}
			this.methods.push(methods[i]);
		}
		interfaces[name] = this;
		this["__ik__"] = InterfaceId();
	};
	/**
	 *  This method checks to see if the object implements this interface
	 *  @name CA.Interfaces.Interface.prototype.Check
	 *  @function
	 *  @param {Object} o the object to check for having implemented this interface
	 *  @return {boolean} a bool indicating if the object implements this interface
	 */
	Interface.prototype["Check"] = function(o) {
		if (typeof (o) != "object" && o!==null) {
			throw new Error("Object expected.");
		}
		if(typeof o["__interfaces__"] !== "undefined" && o["__interfaces__"].indexOf(this["__ik__"])!=-1){
			return true;
		}
		for ( var i = 0; i < this.methods.length; i++) {
			if (typeof (o[this.methods[i]]) != "function") {
				return false;
			}
		}
		if(CA.Interfaces["USE_INTERFACE_KEYS"]){
			if(typeof o["__interfaces__"] === "undefined"){
				o["__interfaces__"] = [];
			}
			o["__interfaces__"].push(this["__ik__"]);
		}
		return true;
	};

	/**
	 *  This method throws an error if o does not implement this interface
	 *  @name CA.Interfaces.Interface.prototype.Ensure
	 *  @function Ensure
	 *  @param {Object} o the object to check for having implemented this interface
	 */
	Interface.prototype["Ensure"] = function(o) {
		if (!this["Check"](o)) {
			throw new Error("Does not implement interfaces:" + this.name);
		}
	};
	/**
	 * Creates an interface class, derived from the book Pro Javascript Design Patterns 
	 * http://apress.com/book/view/159059908x
	 * @function Create
	 * @param {string} name The name of the interface
	 * @param {array} methods An array of method names (strings) that must exist on an object to "implement" this interface
	 * @return {Object} the interface object
	 */
	CA.Interfaces.Create = function(name, methods) {
		return new Interface(name, methods);
	};
	/**
	 * Creates an interface class, derived from the book Pro Javascript Design Patterns 
	 * http://apress.com/book/view/159059908x
	 * @function Get
	 * @param {string} name The name of the interface
	 * @return {Object} the interface object
	 */
	CA.Interfaces.Get = function(name) {
		return interfaces[name];
	};
	/**
	 *  This method checks to see if the object implements this interface.  NOTE: additional arguments
	 *  following params with the names of the interfaces being checked against o
	 *  @function Check
	 *  @param {Object} o the object to check for having implemented the interface(s)
	 *  @return {boolean} a bool indicating if the object implements the interface(s)
	 */
	CA.Interfaces.Check = function() {
		if (arguments.length < 2) {
			throw new Error("Expected at least two arguments.");
		}
		var instance = arguments[0];
		for ( var i = 1; i < arguments.length; i++) {
			var interfaceName = arguments[i];
			var iface = interfaces[interfaceName];
			if (iface) {
				if (!iface["Check"](instance)) {
					return false;
				}
			} else {
				throw new Error("No such interface defined:" + interfaceName);
			}
		}
		return true;
	};
	/**
	 *  This method throws an error if o does not implement the interface(s)
	 *  one or more arguments following params with the names of the interfaces being checked against o
	 *  @function Ensure
	 *  @param {Object} o the object to check for having implemented the interface(s)
	 */
	CA.Interfaces.Ensure = function() {
		if (arguments.length < 2) {
			throw new Error("Expected at least two arguments.");
		}
		var instance = arguments[0];
		for ( var i = 1; i < arguments.length; i++) {
			var interfaceName = arguments[i];
			var iface = interfaces[interfaceName];
			if (iface) {
				iface["Ensure"](instance);
			} else {
				throw new Error("No such interface defined:" + interfaceName);
			}
		}
		return true;
	};
})();
(function() {
	var _call = function(args, scope, fn) {
		var slots = args.callee["__signal_slots__"].slice(0);
		var arglist = Array.prototype.slice.call(args,0);
		arglist.push(scope);
		for ( var j = 0; j < slots.length; j++) {
			var obj = slots[j][0];
			if (typeof obj === "undefined") {
				obj = scope;
			}
			var fun = slots[j][1];
			try {
				fun.apply(obj, arglist);
			} catch (e) {
			}
		}
		if (typeof fn === "function") {
			return fn.apply(scope, args);
		}
	};
	var _connect = function(fun, obj) {
		var slots = this["__signal_slots__"];
		slots.push( [ obj, fun ]);
	};
	var _disconnect = function(fun, obj) {
		var slots = this["__signal_slots__"];
		var i;
		for (i = 0; i < slots.length; i++) {
			if (obj == slots[i][0] && fun == slots[i][1]) {
				break;
			}
		}
		if (i < slots.length) {
			slots.splice(i, 1);
			return true;
		}
		return false;
	};
	var _disconnect_all = function() {
		arguments.callee["__signal_slots__"] = [];
	};
	/**
	 * @static
	 */
	var SignalFunction = {
		/**
		 * Connects a function to this signal
		 * @function Connect
		 * @param {Function} fn The function to be called on the signal
		 * @param {Object} scope The scope that fn should be called with.  If not defined, will recieve the scope of the signal.
		 */
		Connect : function(fn,scope){},
		/**
		 * Disconnects a function to this signal
		 * @function Disconnect
		 * @param {Function} fn The function connected to the signal
		 * @param {Object} scope The scope that fn was connected with
		 */
		Disconnect : function(fn,scope){},
		/**
		 * Disconnects all functions from this signal
		 * @function DisconnectAll
		 */
		DisconnectAll : function(){}		
	};
	/**
	 * A Factory function that returns a signalfunction object
	 * @function
	 * @param {Function} fn An optional function the signal wraps and uses for the return value
	 * @return {SignalFunction}
	 */
	CA.Signal = function(fn) {
		var _signal = function() {
			return _call(arguments, this, fn);
		};
		_signal["__signal_slots__"] = [];
		_signal["Connect"] = _connect;
		_signal["Disconnect"] = _disconnect;
		_signal["DisconnectAll"] = _disconnect_all;
		return _signal;
	};
})();

(function() {
	/**
	 * @namespace
	 */
	CA.Workflows = {};
	function ConfigError(name) {
		return new Error(name + " config option(s) is required");
	}
	function CheckConfig(o, required) {
		var errors = [];
		for ( var i = 0; i < required.length; i++) {
			var option = required[i];
			if (!o[option]) {
				errors.push(option);
			}
		}
		if (errors.length > 0) {
			throw ConfigError(errors.join(","));
		}
	}
	var workflows_by_type = {};
	var workflows_by_name = {};
	function RegisterWorkflow(w) {
		if (workflows_by_name[w["name"]]) {
			throw new Error(w["name"] + " is not a unique workflow name.");
		}
		workflows_by_name[w["name"]] = w;
		if (!workflows_by_type[w["type"]]) {
			workflows_by_type[w["type"]] = [];
		}
		workflows_by_type[w["type"]].push(w);
	}
	function UnregisterWorkflow(w) {
		delete workflows_by_name[w["name"]];
		delete workflows_by_type[w["type"]][w["name"]];
	}
	/**
	 * A transition within the workflow. This object is not directly
	 * constructed, instead use AddTransition
	 * 
	 * @class
	 */
	CA.Workflows.TransitionConfig = {	
		/**
		 * (Required) the name of the transition
		 * @type string
		 */
		name : "",
		/**
		 * (Required) the state the content is coming from
		 * @type string
		 */
		from_state : "",
		/**
		 * (Required) the state the content is going to
		 * @type string
		 */
		to_state : "",
		/**
		 * A function that is called with the content object being tested
		 * for this transition and additional info. It returns true if the object
		 * can make this transition, and false if not.
		 * @param {Object} content the object for which valid transitions are being looked up for
		 * @param {Object} info additional information that will be passed on to checks and callbacks
		 */
		check : function(content,info){},
		/**
		 * A function that will be called with the content object, the
		 * related workflow, and an additional info argument when the object makes
		 * this transition.
		 * @param {Object} content the object for which valid transitions are being looked up for
		 * @param {CA.Workflows.Workflow} workflow the workflow
		 * @param {Object} info additional information that will be passed on to checks and callbacks
		 */
		callback : function(content,workflow,info){}
	};
	/**
	 * @class
	 */
	CA.Workflows.StateConfig = {
		/** @lends CA.Workflows.StateConfig.prototype */
		/**
		 * (Required) the name of the state
		 * @type string 
		 */
		name : "",
		/**
		 * (Optional) a function that will be called with the content object, the
		 * related workflow, and an additional info argument when the object
		 * transitions to this state.
		 * @param {Object} content the object for which valid transitions are being looked up for
		 * @param {CA.Workflows.Workflow} workflow the workflow
		 * @param {Object} info additional information that will be passed on to checks and callbacks
		 */
		callback : function(content,workflow,info){}
	};
	/**
	 * @class
	 */
	CA.Workflows.WorkFlowConfig = {	
		/**
		 * (Required) the 'type' of the workflow
		 * @type string 
		 */
		type : "",
		/**
		 * (Required) the name of the workflow
		 * @type string 
		 */
		name : "",	
		/**
		 * (Required) the name of the initial state in the workflow
		 * @type string
		 */
		initial : "",	
		/**
		 * (Required) the name of the attribute that the current statename will be
	 	 * stored in on objects participating in workflow
		 * @type string
		 */
		attribute : "",	
		/**
		 * (Optional) a description of this workflow
		 * @type string
		 */
		description : "",
		/**
		 * (Optional) an array of interfaces for content that this workflow supports
		 * @type array
		 */
		content_types : []
	};
	/**
	 * A function that has no
	 * 
	 * @class Workflow
	 * @constructor
	 * @param {CA.Workflows.WorkFlowConfig} o the config object
	 * @param {boolean} register Indicates if the workflow should be registered during construction
	 */
	CA.Workflows.Workflow = function(config, register) {
		CA.apply(config, this, true);
		CheckConfig(this, [ "type", "name", "initial", "attribute" ]);
		this["config"] = config;
		var states = this["states"] || [];
		var transitions = this["transitions"] || [];
		this["states"] = {};
		this["transitions"] = {};
		this["transition_lookup"] = {};
		for ( var i = 0; i < states.length; i++) {
			this["AddState"](states[i]);
		}
		for ( var j = 0; j < transitions.length; j++) {
			this["AddTransition"](transitions[j]);
		}
		if (register) {
			this["Register"]();
		}
	};
	/**
	 * The workflow's description
	 *  @name CA.Workflows.Workflow.prototype.description
	 *  @type string
	 */
	CA.Workflows.Workflow.prototype["description"] = "";
	/**
	 * List of Interfaces that can participate in this workflow
	 *  @name CA.Workflows.Workflow.prototype.content_types
	 *  @type array
	 */
	CA.Workflows.Workflow.prototype["content_types"] = [];
	/**
	 * Registers the workflow for use
	 * @name CA.Workflows.Workflow.prototype.Register
	 * @function
	 */
	CA.Workflows.Workflow.prototype["Register"] = function() {
		RegisterWorkflow(this);
	};
	/**
	 * Unregisters the workflow
	 * @name CA.Workflows.Workflow.prototype.Unregister
	 * @function
	 */
	CA.Workflows.Workflow.prototype["Unregister"] = function() {
		UnregisterWorkflow(this);
	};
	/**
	 * Adds a new state to the workflow
	 * @name CA.Workflows.Workflow.prototype.AddState
	 * @function
	 * @param {CA.Workflows.StateConfig} config A config object
	 */
	CA.Workflows.Workflow.prototype["AddState"] = function(config) {
		CheckConfig(config, [ "name" ]);
		if (this["states"][config["name"]]) {
			throw new Error("This state name/alias is taken for this workflow.");
		}
		this["states"][config["name"]] = config;
	};
	/**
	 * Adds a new transition to the workflow
	 * @name CA.Workflows.Workflow.prototype.AddTransition
	 * @function
	 * @param {CA.Workflows.TransitionConfig} config config object
	 */
	CA.Workflows.Workflow.prototype["AddTransition"] = function(config) {
		CheckConfig(config, [ "from_state", "to_state", "name" ]);
		if (this["transitions"][config["name"]]) {
			throw new Error("This transition name is taken for this workflow.");
		}
		if (!this["states"][config["from_state"]]) {
			throw new Error(
					"The 'from_state' for this transition does not exist.");
		}
		if (!this["states"][config["to_state"]]) {
			throw new Error(
					"The 'to_state' for this transition does not exist.");
		}
		var froms = CA.NameSpace(config["from_state"], this["transition_lookup"]);
		if (!froms[config["to_state"]]) {
			froms[config["to_state"]] = [];
		}
		froms[config["to_state"]].push(config);
		this["transitions"][config["name"]] = config;
	};
	/**
	 * Tests to see if the workflow accepts this Object/Interface
	 * @name CA.Workflows.Workflow.prototype.Accepts
	 * @function
	 * @param {Object/String} obj If it is an object, the object is tested to see if it
	 *            meets any of the interfaces in the workflows content_types. If
	 *            content_types is empty, this function returns true. If obj is
	 *            a string, the function checks to see if it is one of the
	 *            strings in content_types.
	 */
	CA.Workflows.Workflow.prototype["Accepts"] = function(obj) {
		if (obj !== null && this["content_types"].length) {
			if (typeof obj === "string" && this["content_types"].indexOf(obj) != -1) {
				return true;
			} else {
				if (CA.Interfaces) {
					for ( var i = 0; i < this["content_types"].length; i++) {
						if (CA.Interfaces.Check(obj,
								this["content_types"][i])) {
							return true;
						}
					}
				} else {
					throw new Error(
							"Cannot verify interface on object as CA.Interfaces is not included.");
				}
			}
			return false;
		}
		return true;
	};
	/**
	 * Gets a list of valid transitions
	 * @name CA.Workflows.Workflow.prototype.GetTransitions
	 * @function
	 * @param {Object} content the object for which valid transitions are being looked up for
	 * @param {Object} info additional information that will be passed on to checks and callbacks
	 * @return {Array} a list of valid transitions
	 */
	CA.Workflows.Workflow.prototype["GetTransitions"] = function(content, info) {
		var from_state = this["GetStateOf"](content);
		var from_ = from_state["name"];
		var froms = CA.NameSpace(from_, this["transition_lookup"]);
		var trans = [];
		for ( var attr in froms) {
			if (froms.hasOwnProperty(attr)) {
				var tos = froms[attr];
				for ( var name in tos) {
					if (tos.hasOwnProperty(name)) {
						var transition = tos[name];
						if (content === null || (transition["check"] && transition["check"](content, info))) {
							trans.push( {
								"transition" : transition,
								"state" : this["states"][attr]
							});
						}
					}
				}
			}
		}
		return trans;
	};
	/**
	 * Initializes the object to the initial state
	 * @name CA.Workflows.Workflow.prototype.Initialize
	 * @function
	 * @param {Object} content the object for which valid transitions are being looked up for
	 * @param {Object} info additional information that will be passed on to checks and callbacks
	 * @return {Object} the initial state
	 */
	CA.Workflows.Workflow.prototype["Initialize"] = function(content, info) {
		var state = this["states"][this["initial"]];
		if (!state) {
			throw new Error("Unknown state:" + this["initial"]);
		}
		content[this["attribute"]] = this["initial"];
		if (state["callback"]) {
			state["callback"](content, this, info);
		}
		return state;
	};
	/**
	 * Gets the state of the content. If the content has not been initialized it
	 * will be initialized to the initial state.
	 * @name CA.Workflows.Workflow.prototype.GetStateOf
	 * @function
	 * @param {Object} content the object for which valid transitions are being looked up for
	 * @param {Object} info additional information that will be passed on to checks and callbacks
	 * @return {Object} the content's state
	 */
	CA.Workflows.Workflow.prototype["GetStateOf"] = function(content, info) {
		var state_name = content[this["attribute"]];
		if (!state_name) {
			return this["Initialize"](content, info);
		}
		var state = this["states"][state_name];
		if (!state) {
			throw new Error("Unknown state:" + state_name);
		}
		return state;
	};
	/**
	 * Resets the content on its current state by calling the states callback
	 * again. If the content has not been initialized it will be initialized to
	 * the initial state.
	 * @name CA.Workflows.Workflow.prototype.Reset
	 * @function
	 * @param {Object} content the object for which valid transitions are being looked up for
	 * @param {Object} info additional information that will be passed on to checks and callbacks
	 * @return {Object} the content's state
	 */
	CA.Workflows.Workflow.prototype["Reset"] = function(content, info) {
		var state_name = content[this["attribute"]] || this["initial"];
		var state = this["states"][state_name];
		if (!state) {
			throw new Error("Unknown state:" + state_name);
		}
		content[this["attribute"]] = state_name;
		if (state["callback"]) {
			state["callback"](content, this, info);
		}
		return state;
	};
	/**
	 * Gets a state by name
	 * @name CA.Workflows.Workflow.prototype.GetState
	 * @function
	 * @param {string} name The name of the state
	 * @return {Object} the state matching name
	 */
	CA.Workflows.Workflow.prototype["GetState"] = function(name) {
		return this["states"][name] || null;
	};
	/**
	 * Gets a transition by name
	 * @name CA.Workflows.Workflow.prototype.GetTransition
	 * @function
	 * @param {string} name The name of the transition
	 * @return {Object} the transition matching name
	 */
	CA.Workflows.Workflow.prototype["GetTransition"] = function(name) {
		return this["transitions"][name] || null;
	};
	/**
	 * Gets a transition by name
	 * @name CA.Workflows.Workflow.prototype.Transition
	 * @function
	 * @param {Object} content the object to be transitioned
	 * @param {string} name The name of the state to be transfered to, or the transition to transfer with
	 * @param {Object} info additional information that will be passed on to checks and callbacks
	 * @return {boolean} success
	 */
	CA.Workflows.Workflow.prototype["Transition"] = function(content, to_thing, info) {
		var from_ = this["GetStateOf"](content);
		var transition = this["transitions"][to_thing];
		if (!transition) {
			var to_ = this["states"][to_thing];
			if (!to_) {
				throw new Error("Unknown state:" + to_thing);
			}
			try {
				var transList = this["transition_lookup"][from_["name"]][to_["name"]].slice(0);
				for ( var i = 0; i < transList.length; i++) {
					var t = transList[i];
					if (!t["check"] || t["check"](content, info)) {
						transition = t;
						break;
					}
				}
			} catch (e) {
			}
		} else {
			if (transition["check"] && !transition["check"](content, info)) {
				transition = null;
			}
		}
		if (!transition) {
			return false;
		} else {
			if (transition["callback"]) {
				transition["callback"](content, this, info);
			}
			var state = this["states"][transition["to_state"]];
			if (state["callback"]) {
				state["callback"](content, this, info);
			}
			content[this["attribute"]] = state["name"];
			return true;
		}
	};
	var WorkFlow = CA.Workflows.Workflow;
	/**
	 * Gets a workflow by name
	 * @function GetWorkflow
	 * @param {string} name The name of the workflow
	 * @return {Workflow} the workflow matching name
	 */
	CA.Workflows.GetWorkflow = function(name) {
		return workflows_by_name[name] || null;
	};
	/**
	 * Gets a workflow by name
	 * @function FindWorkflow
	 * @param {Object/String} obj An object or string (interface name) to be used in the workflow
	 * @param {string} wType The type of the workflow
	 * @return {Workflow} the matching workflow
	 */
	CA.Workflows.FindWorkflow = function(o, wType) {
		var wfList = workflows_by_type[wType];
		if (wfList) {
			for ( var i = 0; i < wfList.length; i++) {
				var workflow = wfList[i];
				if (workflow["Accepts"](o)) {
					return workflow;
				}
			}
		}
		return null;
	};
})();

/**
 * @namespace Provides facilities for registering and looking up adapters
 */
CA.Adapters = {};
(function() {
	var registry = [];//private
	/**
	 * Method for adding an adaptation
	 * @name CA.Adapters.Register
	 * @function
	 * @param {string} from_ The Interface name being adapted from
	 * @param {string} to_ The Interface name being adapted to
	 * @param {Function} adapter The function that performs the adaptation
	 */
	CA.Adapters["Register"] = function(from_, to_, adapter) {
			registry.push( {
				'from_' : from_,
				'to_' : to_,
				'adapter' : adapter
			});
	};
	/**
	 * Adapts an object to a given interface
	 * @name CA.Adapters.Adapt
	 * @function
	 * @param {Object} obj The object being adapted
	 * @param {string} to_ The Interface name the object should be adapted to
	 * @param {boolean} ensure An optional parameter that can force a check on the adaptation to ensure it implements the interface
	 * @return {Object} The adapted object
	 */
	 CA.Adapters["Adapt"] = function(obj, to_, ensure) {
	 	var chk = CA.Interfaces["Check"];
		if (chk(obj, to_)) {
			return obj;
		}
		for ( var i = 0; i < registry.length; i++) {
			var entry = registry[i];
			if (to_ == entry["to_"]) {
				if (chk(obj, entry["from_"])) {
					var result = entry["adapter"](obj);
					if (ensure) {
						CA.Interfaces["Ensure"](result, to_);
					}
					return result;
				}
			}
		}
		throw new Error("No Adaptation Found");
	};
})();
(function() {
	var factories = {};
	var factoriesByName = {};
	function GetFactoryLookup(interfaceName, qualifier) {
		var factory_lookup = factories;
		if (qualifier) {
			if (typeof (factoriesByName[qualifier]) == "undefined") {
				factoriesByName[qualifier] = {};
			}
			factory_lookup = factoriesByName[qualifier];
		}
		return factory_lookup;
	}
	/**
	 * @class
	 * @static
	 */
	CA.Factories = {
		/**
		 * Adds a factory
		 * @function Register
		 * @param {string} interfaceName The name of the interface that objects the factory produces implements
		 * @param {Function} fn The factory
		 * @param {string} qualifier An optional argument that can provide a qualifier for this factory
		 */
		Register : function(interfaceName, fn, qualifier) {
			var lookup = GetFactoryLookup(interfaceName, qualifier);
			if (CA.Interfaces.Get(interfaceName)) {
				if (lookup[interfaceName]) {
					throw new Error("Factory for Interface[" + interfaceName + "] already exists.");
				} else {
					lookup[interfaceName] = fn;
				}
			} else {
				throw new Error("Interface[" + interfaceName + "] does not exist.");
			}
		},
		/**
		 * Invoke a factory by the interface it produces
		 * additional arguments will be passed to the factory function
		 * @function Create
		 * @param {string} interfaceName The name of the interface that objects the factory produces implements
		 * @param {string} qualifier An argument that provides a qualifier for this factory (null if no qualifier)
		 * @return {Object} the result of invoking the factory and implements the interface
		 */
		Create : function(interfaceName, qualifier) {
			var lookup = GetFactoryLookup(interfaceName, qualifier);
			if (lookup[interfaceName]) {
				var iface = CA.Interfaces.Get(interfaceName);
				var args = Array.prototype.slice.call(arguments,2);
				var instance = lookup[interfaceName].apply(null, args);
				iface["Ensure"](instance);
				return instance;
			} else {
				throw new Error("Factory for Interface[" + interfaceName + "] does not exist.");
			}
		}
	};
})();
(function() {
	var services = {};
	var servicesByName = {};
	function GetServiceLookup(interfaceName, qualifier) {
		var service_lookup = services;
		if (qualifier) {
			if (typeof (servicesByName[qualifier]) == "undefined") {
				servicesByName[qualifier] = {};
			}
			service_lookup = servicesByName[qualifier];
		}
		return service_lookup;
	}
	/**
	 * @namespace
	 */
	CA.Services = {
		/**
		 * Adds a service
		 * @function Register
		 * @param {string} interfaceName The name of the interface that objects the factory produces implements
		 * @param {Object} service The service
		 * @param {string} qualifier An optional argument that can provide a qualifier for this service
		 * @param {boolean} override a bool to indicate if this service should override an existing service for the same interface/qualifier
		 */
		Register : function(interfaceName, service, qualifier, override) {
			var lookup = GetServiceLookup(interfaceName, qualifier);
			var iface = CA.Interfaces.Get(interfaceName);
			if (iface) {
				if (lookup[interfaceName]) {
					if (!override) {
						throw new Error("Service for Interface[" + interfaceName + "] already exists.");
					}
				}
				iface["Ensure"](service);
				lookup[interfaceName] = service;
			} else {
				throw new Error("Interface[" + interfaceName + "] does not exist.");
			}
		},
		/**
		 * Invoke a factory by the interface it produces
		 * @function Get
		 * @param {string} interfaceName The name of the interface that the service implements
		 * @param {string} qualifier An argument that provides a qualifier for this service (null if no qualifier)
		 * @return {Object} the service 
		 */
		Get : function(interfaceName, qualifier) {
			var lookup = GetServiceLookup(interfaceName, qualifier);
			if (lookup[interfaceName]) {
				return lookup[interfaceName];
			} else {
				throw new Error("Service for Interface[" + interfaceName + "] does not exist.");
			}
		}
	};
})();
(function() {
	/**
	 * Interface defined for a Unique ID Provider.  A default provider for in browser UIDs has been
	 * provided for the qualifier "default".
	 * @class IUIDProvider
	 * @static
	 */
	var IUIDProvider = {
		/**
		 * Method that returns a unique id
		 * @function GetUID
		 * @return {string} a (browser) unique id
		 */
		GetUID : function(){}			
	};
	CA.Interfaces.Create("IUIDProvider", [ "GetUID" ]);
	/**
	 * @namespace
	 */
	CA.UID = {};
	CA.UID.DefaultProvider = {};
	var freeUIDs = [];
	CA.UID.DefaultProvider["AddUIDS"] = function(new_uids) {
		for ( var i = 0; i < new_uids.length; i++) {
			freeUIDs.push(new_uids[i]);
		}
	};
	/**
	 * Method that returns a unique id
	 * @function GetUID
	 * @return {string} a (browser) unique id
	 */
	CA.UID.DefaultProvider["GetUID"] = function() {
		if (freeUIDs.length > 0) {
			return freeUIDs.shift();
		}
		throw new Error("Out of UIDs to issue.");
	};
	CA.Services.Register("IUIDProvider", CA.UID.DefaultProvider, "default");
	/**
	 * Returns a function that will generate a counter based ID with the prefix provided
	 * @function Counter
	 * @param {string} prefix The prefix of the auto generated id that the returned function will provide
	 * @return {Function} the function that will return the counter based id generator
	 */
	CA.UID.Counter = function(prefix) {
		if (typeof (prefix) !== "string") {
			prefix = "";
		}
		var i = 0;
		return function() {
			var val = prefix + i;
			i++;
			return val;
		};
	};
})();
(function() {
	var components = {};
	/**
	 * Interface defined for a component.
	 */
	var IComponent = {
		/**
		 * Initializes the component
		 * @function InitializeComponent
		 * @param {Object} manager The component manager
		 */
		InitializeComponent : function(manager) {
		},
		/**
		 * Sets the component cmpid
		 * @function SetComponentID
		 * @param {string} cmpid The component id
		 */
		SetComponentID : function(cmpid) {
			this.__ca_component__id = cmpid;
		},
		/**
		 * Gets the component id
		 * @function GetComponentID
		 * @return {string} The component id
		 */
		GetComponentID : function() {
			return this.__ca_component__id;
		}
	};
	var BaseComponent = IComponent;
	CA.Interfaces.Create("IComponent", [ "InitializeComponent",
			"SetComponentID", "GetComponentID" ]);
	/**
	 * Component Manager
	 * @class
	 * @static
	 */
	CA.Components = {
		/**
		 * Gets a component by ID
		 * @function Get
		 * @param {string} component_id
		 * @return {Object} The component
		 */
		Get : function(component_id) {
			if (typeof (components[component_id]) !== "undefined") {
				return components[component_id];
			}
			return null;
		},
		/**
		 * Adds to an object the methods to allow it to participate as a
		 * component
		 * @function Decorate
		 * @param {Object} cmp The object to be decorated with component functions
		 */
		Decorate : function(cmp) {
			for ( var attr in BaseComponent) {
				if (BaseComponent.hasOwnProperty(attr) && !cmp.hasOwnProperty(attr)) {
					cmp[attr] = BaseComponent[attr];
				}
			}
		},
		/**
		 * Registers a component with the framework
		 * @function Register
		 * @param {Object} cmp The component being registered
		 */
		Register : function(cmp) {
			CA.Interfaces.Ensure(cmp, "IComponent");
			var component_id = CA.Services.Get("IUIDProvider", "default")["GetUID"]();
			cmp["SetComponentID"](component_id);
			components[component_id] = cmp;
			if (CA.ComponentCommunications) {
				CA.ComponentCommunications["_setupComponent"](cmp);
			}
			cmp["InitializeComponent"](this);
		},
		/**
		 * Unregisters a component from the framework
		 * @function Unregister
		 * @param {Object} cmp The component being unregistered
		 */
		Unregister : function(cmp) {
			CA.Interfaces.Ensure(cmp, "IComponent");
			var component_id = cmp["GetComponentID"]();
			delete components[component_id];
			if (CA.ComponentCommunications) {
				CA.ComponentCommunications["UnregisterAll"](cmp);
			}
		}
	};
})();

(function() {
	CA.Interfaces.Create("IBroadcastHandlerComponent", [
			"InitializeComponent", "SetComponentID", "GetComponentID",
			"OnBroadcast" ]);
	var events = {};
	var targets = {};
	var components_to_groups = {};
	var groups = {};
	var _NULL = "__CA_SERVICES__NULL__";
	function EventIndex(items, fn, scope) {
		var index = -1;
		for ( var i = 0; i < items.length; i++) {
			var item = items[i];
			if (item["fn"] == fn && item["scope"] == scope) {
				index = i;
				break;
			}
		}
		return index;
	}
	/**
	 * @class
	 * @static
	 */
	CA.ComponentCommunications = {
		/**
		 * Returns a value that represents an "Any" match for components
		 * @function Any
		 * @return {string} a the value
		 */
		Any : function() {
			return _NULL;
		},
		_getTarget : function(target) {
			var targetType = typeof (target);
			if (targetType === "undefined" || target === null) {
				return _NULL;
			} else if (targetType == "string") {
				return target;
			} else if (CA.Interfaces.Check(target, "IComponent")) {
				return target["GetComponentID"]();
			}
			throw new Error("Cannot handle type of object passed.");
		},
		/**
		 * A method that sends a message (invokes a function) on a component if
		 * it exists.  Additional arguments are passed on as part of the message
		 * @function SendMessage
		 * @param {string} component_id The component id
		 * @param {string} message The message (function name) of the target component
		 * @return {boolean} indicating if the message was successfully sent
		 */
		SendMessage : function(component_id, message) {
			var cmp = CA.Components.Get(component_id);
			if (cmp) {
				if (typeof (cmp[message]) === "function") {
					var args = Array.prototype.slice.call(arguments,2);
					if (cmp[message]) {
						cmp[message].apply(cmp, args);
						return true;
					}
				}
			}
			return false;
		},
		/**
		 * Connect to an event on a target
		 * @function Connect
		 * @param {string} target The target (component id) to connect to
		 * @param {string} event The event being listened for
		 * @param {Function} fn The handler for the event
		 * @param {Object} scope The scope to invoke the handler with
		 */
		Connect : function(target, event, fn, scope) {
			target = this._getTarget(target);
			if (typeof (scope) === "undefined") {
				scope = null;
			}
			eventEntries = CA.NameSpace(event, events);
			if (typeof (eventEntries[target]) === "undefined") {
				eventEntries[target] = [];
			}
			var entries = eventEntries[target];
			if (EventIndex(entries, fn, scope) == -1) {
				entries.push( {
					"fn" : fn,
					"scope" : scope,
					"target" : target
				});
			}
		},
		/**
		 * Disconnect from an event on a target
		 * @function Disconnect
		 * @param {string} target The target (component id) to disconnect from
		 * @param {string} event The event being listened for
		 * @param {Function} fn The handler for the event
		 * @param {Object} scope The scope to invoke the handler with
		 */
		Disconnect : function(target, event, fn, scope) {
			target = this._getTarget(target);
			eventEntries = CA.NameSpace(event, events);
			if (typeof (eventEntries[target]) === "undefined") {
				return;
			}
			if (typeof (scope) === "undefined") {
				scope = null;
			}
			var entries = eventEntries[target];
			var index = EventIndex(entries, fn, scope);
			if (index != -1) {
				entries.splice(index, 1);
			}
			if (entries.length === 0) {
				delete eventEntries[target];
			}
		},
		/**
		 * A method that fires an event on a component additional arguments 
		 * are passed on as part of the event
		 * @function FireEvent
		 * @param {string} target The target (component id)
		 * @param {string} event The event to throw 
		 */
		FireEvent : function(target, event) {
			target = this._getTarget(target);
			targets = [ target ];
			if (target !== _NULL) {
				targets.push(_NULL);
			}
			eventEntries = CA.NameSpace(event, events);
			var args = Array.prototype.slice.call(arguments,2);
			for ( var k = 0; k < targets.length; k++) {
				target = targets[k];
				if (typeof (eventEntries[target]) === "undefined") {
					continue;
				}
				var listeners = eventEntries[target].slice(0);
				for ( var j = 0; j < listeners.length; j++) {
					var entry = listeners[j];
					try {
						entry["fn"].apply(entry["scope"], args);
					} catch (e) {

					}
				}
			}
		},
		_setupComponent : function(cmp) {
			if (CA.Interfaces.Check(cmp, "IBroadcastHandlerComponent")) {
				var component_id = cmp["GetComponentID"]();
				if (typeof (components_to_groups[component_id]) === "undefined") {
					components_to_groups[component_id] = [];
				} else {
					throw new Error("Component has been registered");
				}
			}
		},
		/**
		 * A method that unregisters all group communication for a component 
		 * @function UnregisterAll
		 * @param {Object} cmp The component
		 */
		UnregisterAll : function(cmp) {
			if (CA.Interfaces.Check(cmp, "IBroadcastHandlerComponent")) {
				var component_id = cmp["GetComponentID"]();
				var cmpGroups = components_to_groups[component_id];
				for ( var i = 0; i < cmpGroups.length; i++) {
					var groupName = cmpGroups[i];
					var group = groups[group];
					var cmp_index = group.indexOf(component_id);
					if (cmp_index != -1) {
						group.splice(cmp_index, 1);
					}
					if (group.length === 0) {
						delete groups[groupName];
					}
				}
				if (CA.Components.Get(component_id) === null) {
					delete components_to_groups[component_id];
				}
			}
		},
		/**
		 * A method that unregisters a group communication for a component
		 * 
		 * @function UnregisterForBroadcast
		 * @param {Object} cmp The component
		 * @param {string} group the group
		 */
		UnregisterForBroadcast : function(cmp, group) {
			CA.Interfaces.Ensure(cmp, "IBroadcastHandlerComponent");
			var component_id = cmp["GetComponentID"]();
			var grouplist = components_to_groups[component_id];
			var index = grouplist.indexOf(group);
			if (index != -1) {
				grouplist.splice(index, 1);
				groupl = groups[group];
				var cmpIndex = groupl.indexOf(component_id);
				groupl.splice(cmpIndex, 1);
				if (groupl.length === 0) {
					delete groups[group];
				}
			}
		},
		/**
		 * A method that registers a group communication for a component
		 * @function RegisterForBroadcast
		 * @param {Object} cmp The component
		 * @param {string} group the group
		 */
		RegisterForBroadcast : function(cmp, group) {
			CA.Interfaces.Ensure(cmp, "IBroadcastHandlerComponent");
			var component_id = cmp["GetComponentID"]();
			var grouplist = components_to_groups[component_id];
			if (grouplist.indexOf(group) == -1) {
				grouplist.push(group);
				if (typeof (groups[group]) === "undefined") {
					groups[group] = [];
				}
				groups[group].push(component_id);
			}
		},
		/**
		 * A method that fires an event on a component
		 * additional arguments will be passed on as part of the broadcast
		 * @function BroadcastMessage
		 * @param {string} group The group to broadcast to
		 */
		BroadcastMessage : function(group) {
			if (typeof (groups[group]) !== "undefined") {
				var grouplist = groups[group].slice(0);
				for ( var i = 0; i < grouplist.length; i++) {
					var cmp = CA.Components.Get(grouplist[i]);
					if (cmp) {
						try {
							cmp["OnBroadcast"].apply(cmp, arguments);
						} catch (e) {
						}
					}
				}
			}
		}
	};
})();

window["CA"] = CA;
CA["Adapters"] = CA.Adapters;
CA["Components"] = CA.Components;
CA.Components["Get"] = CA.Components.Get;
CA.Components["Decorate"] = CA.Components.Decorate;
CA.Components["Register"] = CA.Components.Register;
CA.Components["Unregister"] = CA.Components.Unregister;
CA["ComponentCommunications"] = CA.ComponentCommunications;
CA.ComponentCommunications["Any"] = CA.ComponentCommunications.Any;
CA.ComponentCommunications["BroadcastMessage"] = CA.ComponentCommunications.BroadcastMessage;
CA.ComponentCommunications["Connect"] = CA.ComponentCommunications.Connect;
CA.ComponentCommunications["Disconnect"] = CA.ComponentCommunications.Disconnect;
CA.ComponentCommunications["FireEvent"] = CA.ComponentCommunications.FireEvent;
CA.ComponentCommunications["RegisterForBroadcast"] = CA.ComponentCommunications.RegisterForBroadcast;
CA.ComponentCommunications["SendMessage"] = CA.ComponentCommunications.SendMessage;
CA.ComponentCommunications["UnregisterAll"] = CA.ComponentCommunications.UnregisterAll;
CA.ComponentCommunications["UnregisterForBroadcast"] = CA.ComponentCommunications.UnregisterForBroadcast;
CA.ComponentCommunications["_setupComponent"] = CA.ComponentCommunications._setupComponent;
CA["Errors"] = CA.Errors;
CA.Errors["Create"]=CA.Errors.Create;
CA["Factories"] = CA.Factories;
CA.Factories["Create"] = CA.Factories.Create;
CA.Factories["Register"] = CA.Factories.Register;
CA["Interfaces"] = CA.Interfaces;
CA.Interfaces["Check"] = CA.Interfaces.Check;
CA.Interfaces["Create"] = CA.Interfaces.Create;
CA.Interfaces["Ensure"] = CA.Interfaces.Ensure;
CA.Interfaces["Get"] = CA.Interfaces.Get;
CA["NameSpace"] = CA.NameSpace;
CA["Services"] = CA.Services;
CA.Services["Register"] = CA.Services.Register;
CA.Services["Get"] = CA.Services.Get;
CA["Signal"] = CA.Signal;
CA["UID"] = CA.UID;
CA["UID"]["Counter"] = CA.UID.Counter;
CA["UID"]["DefaultProvider"] = CA.UID.DefaultProvider;
CA["Workflows"] = CA.Workflows;
CA["Workflows"]["FindWorkflow"] = CA.Workflows.FindWorkflow;
CA["Workflows"]["GetWorkflow"] = CA.Workflows.GetWorkflow;
CA["Workflows"]["Register"] = CA.Workflows.Register;
CA["Workflows"]["Workflow"] = CA.Workflows.Workflow;


